﻿using System.Text;
using Dm.util;
using SqlSugar;
using WeDonekRpc.Helper;

namespace WeDonekRpc.SqlSugar.VirtualQuery
{
    internal class ConditionalFunc : ICustomConditionalFunc
    {
        private readonly WhereCol _model;
        private readonly VirtualQuery _Query;
        private static readonly char _comma = ',';
        private static readonly Dictionary<ConditionalType, string> _Conditional = new Dictionary<ConditionalType, string>()
        {
            {ConditionalType.Equal,"=" },
            {ConditionalType.NoEqual,"!=" },
            {ConditionalType.Like,"like" },
            {ConditionalType.LikeLeft,"like" },
            {ConditionalType.LikeRight,"like" },
            {ConditionalType.GreaterThan,">" },
            {ConditionalType.GreaterThanOrEqual,">=" },
            {ConditionalType.LessThan,"<" },
            {ConditionalType.LessThanOrEqual,"<=" },
            {ConditionalType.NoLike,"not link" },
             {ConditionalType.EqualNull,"is null" },
        };
        private int _Index = 0;
        public ConditionalFunc ( WhereCol model, VirtualQuery query )
        {
            this._Query = query;
            this._model = model;
        }

        public KeyValuePair<string, SugarParameter[]> GetConditionalSql ( ConditionalModel json, int index )
        {
            this._Index = index * 200;
            if ( this._model.Table.HasValue == false )
            {
                return this._CreateSql(this._model.Name);
            }
            WhereTable table = this._model.Table.Value;
            if ( this._Query.Table.TryGetValue(table.Table, out string alla) )
            {
                string n = alla + "." + this._model.Name;
                return this._CreateSql(n);
            }
            else
            {
                string n = "table_" + index;
                KeyValuePair<string, SugarParameter[]> t = this._CreateSql(n + "." + this._model.Name);
                string sql = string.Format("exists (select {1}.{3} from {0}(nolock) as {1}  where {2}.{3}={1}.{4} and {5}) ", table.Table, n, this._Query.MainTable, table.Foreign, table.Key, t.Key);
                return new KeyValuePair<string, SugarParameter[]>(sql, t.Value);
            }
        }
        private KeyValuePair<string, SugarParameter[]> _CreateSql ( string name )
        {
            if ( this._model.ConditionalType == ConditionalType.InLike )
            {
                if ( this._model.Value != null )
                {
                    string key = "@tk" + this._Index++;
                    SugarParameter param = new SugarParameter(key, this._model.Value, this._model.DbType);
                    string sql = string.Format("{0} like {2}   ", name, _Conditional[this._model.ConditionalType], key);
                    return new KeyValuePair<string, SugarParameter[]>(sql, new SugarParameter[]
                    {
                        param
                    });
                }
                else
                {
                    StringBuilder sql = new StringBuilder("(");
                    Array arr = (Array)this._model.Value;
                    SugarParameter[] param = arr.ConvertAll(c =>
                    {
                        string key = "@tm" + this._Index++;
                        _ = sql.AppendFormat("({0} like {1}) or ", name, key);
                        return new SugarParameter(key, c, this._model.DbType);
                    });
                    _ = sql.Remove(sql.Length - 4, 4);
                    _ = sql.Append(")   ");
                    return new KeyValuePair<string, SugarParameter[]>(sql.toString(), param);
                }
            }
            else if ( this._model.Func == FuncType.Between )
            {
                Array arr = (Array)this._model.Value;
                SugarParameter[] param = new SugarParameter[]
                {
                        new SugarParameter("@time_" + this._Index++, arr.GetValue(0), this._model.DbType),
                        new SugarParameter("@time_" + this._Index++, arr.GetValue(1), this._model.DbType),
                };
                string sql = string.Format("{0} between {1} and {2} ", name, param[0].ParameterName, param[1].ParameterName);
                return new KeyValuePair<string, SugarParameter[]>(sql, param);
            }
            else if ( this._model.ConditionalType == ConditionalType.In || this._model.ConditionalType == ConditionalType.NotIn )
            {
                StringBuilder sql = new StringBuilder(name);
                if ( this._model.ConditionalType == ConditionalType.In )
                {
                    _ = sql.Append(" in (");
                }
                else
                {
                    _ = sql.Append(" not in (");
                }
                Array arr = (Array)this._model.Value;
                SugarParameter[] param = arr.ConvertAll(c =>
                {
                    string key = "@td" + this._Index++;
                    _ = sql.Append(key);
                    _ = sql.Append(_comma);
                    return new SugarParameter(key, c, this._model.DbType);
                });
                _ = sql.Remove(sql.Length - 1, 1);
                _ = sql.Append(")   ");
                return new KeyValuePair<string, SugarParameter[]>(sql.toString(), param);
            }
            else
            {
                string key = "@ts" + this._Index++;
                object val = null;
                if ( this._model.ConditionalType == ConditionalType.Like || this._model.ConditionalType == ConditionalType.NoLike )
                {
                    val = "%" + Convert.ToString(this._model.Value) + "%";
                }
                else if ( this._model.ConditionalType == ConditionalType.LikeLeft )
                {
                    val = Convert.ToString(this._model.Value) + "%";
                }
                else if ( this._model.ConditionalType == ConditionalType.LikeRight )
                {
                    val = "%" + Convert.ToString(this._model.Value);
                }
                else
                {
                    val = _Format(Convert.ToString(this._model.Value), this._model.DbType);
                }
                SugarParameter param = new SugarParameter(key, val, this._model.DbType);
                string sql = string.Format("{0} {1} {2}   ", name, _Conditional[this._model.ConditionalType], key);
                return new KeyValuePair<string, SugarParameter[]>(sql, new SugarParameter[]
                {
                    param
                });
            }
        }

        private static object _Format ( string val, System.Data.DbType type )
        {
            if ( type == System.Data.DbType.DateTime || type == System.Data.DbType.Date )
            {
                return Tools.PaseDateTime(val);
            }
            else if ( type == System.Data.DbType.Decimal )
            {
                return decimal.Parse(val);
            }
            else if ( type == System.Data.DbType.Int16 )
            {
                return short.Parse(val);
            }
            else if ( type == System.Data.DbType.Int64 )
            {
                return long.Parse(val);
            }
            else if ( type == System.Data.DbType.Int32 )
            {
                return int.Parse(val);
            }
            else if ( type == System.Data.DbType.Single )
            {
                return float.Parse(val);
            }
            else if ( type == System.Data.DbType.Double )
            {
                return double.Parse(val);
            }
            else if ( type == System.Data.DbType.Byte )
            {
                return byte.Parse(val);
            }
            return val;
        }
    }
}
